import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description:
 * @ClassName: ThreadPoolTest
 * @Author: chenyu
 * @Date: 2025/3/21 10:09
 */
public class ThreadPoolTest {
    public static void main(String[] args) {
        //keepAliveTime 超时时间 用在什么地方的
        //corePoolSize 核心线程数，可以认为线程池里至少会有10个线程，
        //当提交一个任务的时候，会先判断当前线程池的核心线程数是否小于设置的核心线程数
        //1.若小于，无论此时是否有空闲下来的核心线程，都会创建一个核心线程去执行这个任务
        //2.若大于等于，会将这个任务放进阻塞队列里
        //核心线程执行完任务后，如何保活？
        // 答案：核心线程执行完任务后，会从阻塞队列里获取任务，因为是阻塞队列，如果队列为空，核心线程会一直阻塞在这里等任务。
        //伪代码如下
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                Runnable task;
//                while ((task = blockingQueue.poll()) != null) {
//                    task.run();
//                }
//            }
//        }).start();

        //当阻塞队列满了，并且核心线程都在执行任务，再往阻塞队列添加任务的时候，这个时候会去创建新的线程来来执行这个任务
        //当创建新的线程达到maximumPoolSize-corePoolSize的时候，再有新的任务添加进来，就会被拒绝掉
        //线程池的四种拒绝策略
        //1.AbortPolicy(默认) 当线程池无法接受新任务时，直接抛出RejectedExecutionException异常。这种策略适用于不允许任务失败的场景，确保开发者能够及时发现并处理问题
        //2.CallerRunsPolicy 当线程池无法接受新任务时，由提交任务的线程直接执行该任务。这种策略可以减缓新任务的提交速度，适用于对性能要求不高、并发量较小的场景
        //3.DiscardOldestPolicy 当线程池无法接受新任务时，丢弃队列中最旧的任务，然后尝试重新提交当前任务。这种策略适用于需要优先处理最新任务的场景，但可能会导致旧任务的数据丢失
        //4.DiscardPolicy 当线程池无法接受新任务时，直接丢弃该任务，且不抛出任何异常。这种策略适用于对任务丢失容忍度较高的场景，例如统计一些非关键数据。

        //创建的新线程执行完任务后，会和核心线程一样，去阻塞队列里获取任务
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 200, 30,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>(500));
//        executor.prestartAllCoreThreads();//提前启动所有核心线程

        executor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("提交任务......");
            }
        });


        //去阻塞队列里获取任务（阻塞队列任务不够或者没有任务）
        //1.当线程池里的线程数超过设置的核心线程数，即wc>corePoolSize
        //第一次循环，有部分线程或者所有线程在keepAliveTime内没有获取到任务，timeOut=true
        //第二次循环，timed为true,timeOut=true,会执行compareAndDecrementWorkerCount方法，使用cas将c-1，然后return null
        //退出外层循环被销毁掉
        //第...次循环 timed为true,timeOut=true,会执行compareAndDecrementWorkerCount方法，使用cas将c-1，然后return null
        //退出外层循环被销毁掉
        //直到剩下的线程数等于核心线程数，此时timed为false,会执行workQueue.take()方法，无限阻塞在这里

//        private Runnable getTask() {
//            boolean timedOut = false; // Did the last poll() time out?
//
//            for (;;) {
//                int c = ctl.get();
//                int rs = runStateOf(c);
//
//                // Check if queue empty only if necessary.
//                if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//                    decrementWorkerCount();
//                    return null;
//                }
//
//                int wc = workerCountOf(c);
//
//                // Are workers subject to culling?
//                boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//
//                if ((wc > maximumPoolSize || (timed && timedOut))
//                        && (wc > 1 || workQueue.isEmpty())) {
//                    if (compareAndDecrementWorkerCount(c))
//                        return null;
//                    continue;
//                }
//
//                try {
//                    Runnable r = timed ?
//                            workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
//                            workQueue.take();
//                    if (r != null)
//                        return r;
//                    timedOut = true;
//                } catch (InterruptedException retry) {
//                    timedOut = false;
//                }
//            }
//        }

        //异常情况
        //当线程执行任务遇到异常时，会执行processWorkerExit，然后执行addWorker(null, false)创建一个新的线程，自己会被销毁，
        //为什么不沿用这个线程，要去创建一个新的线程呢？这里就要说到异常机制了，线程池里会捕捉异常，如果不抛异常，那外层留给程序员
        //自定义的异常处理机制就会没用，所以只能把异常抛出来，所以当前线程会退出循环。所以必须创建一个新的线程
//        final void runWorker(ThreadPoolExecutor.Worker w) {
//            Thread wt = Thread.currentThread();
//            Runnable task = w.firstTask;
//            w.firstTask = null;
//            w.unlock(); // allow interrupts
//            boolean completedAbruptly = true;
//            try {
//                while (task != null || (task = getTask()) != null) {
//                    w.lock();
//                    // If pool is stopping, ensure thread is interrupted;
//                    // if not, ensure thread is not interrupted.  This
//                    // requires a recheck in second case to deal with
//                    // shutdownNow race while clearing interrupt
//                    if ((runStateAtLeast(ctl.get(), STOP) ||
//                            (Thread.interrupted() &&
//                                    runStateAtLeast(ctl.get(), STOP))) &&
//                            !wt.isInterrupted())
//                        wt.interrupt();
//                    try {
//                        beforeExecute(wt, task);
//                        Throwable thrown = null;
//                        try {
//                            task.run();
//                        } catch (RuntimeException x) {
//                            thrown = x; throw x;
//                        } catch (Error x) {
//                            thrown = x; throw x;
//                        } catch (Throwable x) {
//                            thrown = x; throw new Error(x);
//                        } finally {
//                            afterExecute(task, thrown);
//                        }
//                    } finally {
//                        task = null;
//                        w.completedTasks++;
//                        w.unlock();
//                    }
//                }
//                completedAbruptly = false;
//            } finally {
//                processWorkerExit(w, completedAbruptly);
//            }
//        }


//        private void processWorkerExit(ThreadPoolExecutor.Worker w, boolean completedAbruptly) {
//            if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
//                decrementWorkerCount();
//
//            final ReentrantLock mainLock = this.mainLock;
//            mainLock.lock();
//            try {
//                completedTaskCount += w.completedTasks;
//                workers.remove(w);
//            } finally {
//                mainLock.unlock();
//            }
//
//            tryTerminate();
//
//            int c = ctl.get();
//            if (runStateLessThan(c, STOP)) {
//                if (!completedAbruptly) {
//                    int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//                    if (min == 0 && ! workQueue.isEmpty())
//                        min = 1;
//                    if (workerCountOf(c) >= min)
//                        return; // replacement not needed
//                }
//                addWorker(null, false);
//            }
//        }

//        executor.shutdown();
//        executor.shutdownNow();
        //两者区别：shutdown会执行完线程池里的任务后，关闭线程；shutdownNow会立即关闭线程
        //当执行executor.shutdown()或者executor.shutdownNow()后，线程池里的线程不是立马关闭，而是改变了线程池的状态
        //线程池里的线程会继续去阻塞队列里获取任务，当发现线程池处于shutdown状态时，会返回null，进而跳出循环，关闭。
        //但是有的线程是阻塞在workQueue.take()这里，并不会得到线程池的状态，那么这些线程该如何关闭呢，通过interruptWorkers()去中断这些线程

    }
}
